﻿using System;
using System.Linq;
using System.Linq.Expressions;

namespace SpecificationPattern
{

    #region 1

    //public interface ISpecification<T>
    //{
    //    bool IsSatisfiedBy(T candidate);

    //    ISpecification<T> And(ISpecification<T> other);

    //    ISpecification<T> Or(ISpecification<T> other);

    //    ISpecification<T> Not();
    //}

    //public abstract class CompositeSpecification<T> : ISpecification<T>
    //{
    //    public abstract bool IsSatisfiedBy(T candidate);

    //    public ISpecification<T> And(ISpecification<T> other)
    //    {
    //        return new AndSpecification<T>(this, other);
    //    }

    //    public ISpecification<T> Or(ISpecification<T> other)
    //    {
    //        return new OrSpecification<T>(this, other);
    //    }

    //    public ISpecification<T> Not()
    //    {
    //        return new NotSpecification<T>(this);
    //    }
    //}

    //public class AndSpecification<T> : CompositeSpecification<T>
    //{
    //    private ISpecification<T> m_one;
    //    private ISpecification<T> m_other;

    //    public AndSpecification(ISpecification<T> x, ISpecification<T> y)
    //    {
    //        m_one = x;
    //        m_other = y;
    //    }

    //    public override bool IsSatisfiedBy(T candidate)
    //    {
    //        return m_one.IsSatisfiedBy(candidate) && m_other.IsSatisfiedBy(candidate);
    //    }
    //}

    //public class OrSpecification<T> : CompositeSpecification<T>
    //{
    //    private ISpecification<T> m_one;
    //    private ISpecification<T> m_other;

    //    public OrSpecification(ISpecification<T> x, ISpecification<T> y)
    //    {
    //        m_one = x;
    //        m_other = y;
    //    }

    //    public override bool IsSatisfiedBy(T candidate)
    //    {
    //        return m_one.IsSatisfiedBy(candidate) || m_other.IsSatisfiedBy(candidate);
    //    }
    //}

    //public class NotSpecification<T> : CompositeSpecification<T>
    //{
    //    private ISpecification<T> m_wrapped;

    //    public NotSpecification(ISpecification<T> x)
    //    {
    //        m_wrapped = x;
    //    }

    //    public override bool IsSatisfiedBy(T candidate)
    //    {
    //        return !m_wrapped.IsSatisfiedBy(candidate);
    //    }
    //}

    //public class FuncSpecification<T> : CompositeSpecification<T>
    //{
    //    private Func<T, bool> funcSpecification = null;

    //    public FuncSpecification(Func<T, bool> func)
    //    {
    //        this.funcSpecification = func;
    //    }

    //    public override bool IsSatisfiedBy(T candidate)
    //    {
    //        return this.funcSpecification(candidate);
    //    }
    //}

    #endregion

    #region 2

    public static class FuncExtensions
    {
        public static Func<T, bool> And<T>(this Func<T, bool> one, Func<T, bool> other)
        {
            return candidate => one(candidate) && other(candidate);
        }

        public static Func<T, bool> Or<T>(this Func<T, bool> one, Func<T, bool> other)
        {
            return candidate => one(candidate) || other(candidate);
        }

        public static Func<T, bool> Not<T>(this Func<T, bool> one)
        {
            return candidate => !one(candidate);
        }
    }

    public class Test
    {
        static Func<int, bool> MorePredicate(Func<int, bool> original)
        {
            return original.Or(i => i > 0);
        }

        static void Mai2n(string[] args)
        {
            var array = Enumerable.Range(-5, 10).ToArray();
            var oddAndPositiveSpec = MorePredicate(i => i > 0);

            foreach (var item in array.Where(i => oddAndPositiveSpec(i)))
            {
                Console.WriteLine(item);
            }
            //var body = Expression.Not(one.Body);
            //new int[] { 1, 2, 3, 4, 5, 6 }.AsQueryable().Where(
        }

    }

    #endregion

}